#pragma once
#include <Rz/Object.h>
#include <Rz/IEquatable.h>
#include "InitializerList.h"
#include "IList.h"

#include <vector>
#include <algorithm>
#include <functional>

namespace Rz { namespace Collections {

template <typename T>
class List :
	public Object,
	public IList<T>,
	public IEquatable<List<T>>
{
	public:
		RZ_RTTI(Rz::Collections, List);
		RZ_RTTI_IMPLEMENTS(Object, IList<T>, IEquatable<List<T>>);
		RZ_RTTI_TEMPLATES(NonObjectType<T>);
		RZ_RTTI_END;

		RZ_TYPEWRAPPER_IMPLEMENT(T);

		List();
		List(SizeType size);
		List(std::initializer_list<T> t);
		List(const InitializerList<T>& t);
		List(const List<T>& list);

		List<T>& operator = (const List<T>& r);

		void Add(const ValueType& item);
		void Add(ValueType&& item);

		template <typename TCI, typename TI>
		void Add(const IEnumerable<T, TCI, TI>& container);
		void Add(const T* data, SizeType count);

		void Clear();

		void Sort(std::function<bool(const T&, const T&)> compareFunc);
		List<T> Select(std::function<bool(const T&)> cmpFn) const;

		// REVIEW: untested
		bool Contains(std::function<bool(const T&)> cmpFn) const;
		bool Contains(ConstReference object) const;
		SizeType IndexOf(ConstReference object) const;

		void Remove(ConstReference object);
		void RemoveAt(SizeType index);

		ConstPointer GetDataPointer() const;
		Pointer GetDataPointer();

		void Reserve(SizeType count);
		void Resize(SizeType count);
		void Resize(SizeType count, ValueType e);

		SizeType GetSize() const;

		bool IsEmpty() const;

		Reference First();
		ConstReference First() const;

		Reference Last();
		ConstReference Last() const;

		template <typename TCI, typename TI>
		static List<T> FromEnumerable(const IEnumerable<T, TCI, TI>& container);

		// IList
		virtual ConstReference At(SizeType index) const override;
		virtual Reference At(SizeType index) override;

		virtual ConstReference operator [] (SizeType index) const override;
		virtual Reference operator [] (SizeType index) override;

		virtual SizeType GetCount() const override;

		// IEquatable
		virtual bool Equals(const List<T>& r) const override;
		virtual bool operator == (const List<T>& r) const override;
		virtual bool operator != (const List<T>& r) const override;;

		// IEnumerable
		RZ_IENUMERABLE_IMPLEMENT_DEFAULT(_items);

	private:
		typedef std::vector<T> VectorType;

		VectorType _items;
};

typedef List<byte_t>	ByteCollection;
typedef List<s32>		Int32Collection;
typedef List<u32>		UInt32Collection;
typedef List<f32>		SingleCollection;

} }

#include "List.inl"

